﻿namespace Sai.Core.Introspection
{
	using System;
	using System.Collections.Generic;
	using System.Linq;

	/// <summary>
	/// Information gathered about an assembly. 
	/// </summary>
	public class IntrospectedAssembly
	{
        // list of references

        // .net runtime

        // attributes for ilonly, 32 bit->64 bit

        // architecture

		private TypeDeclarationCollection types = new TypeDeclarationCollection();
		private NamespaceTypeNameLookup dictionary = new NamespaceTypeNameLookup();

        private List<AssemblyReference> _references = new List<AssemblyReference>();

		public IntrospectedAssembly(string name, string version)
		{
			this.Name = name;
			this.Version = new Version(version);
		}

		public IntrospectedAssembly(string name, Version version)
		{
			this.Name = name;
			this.Version = version;
		}

		public string Name
		{
			get;
			private set;
		}

		public Version Version
		{
			get;
			private set;
		}

        public string RuntimeVersion
        {
            get;
            set;
        }

        public int TypeCount
        {
            get { return this.types.Count; }
        }

		public void Add(ITypeDeclaration discoveredType)
		{
			this.types.Add(discoveredType);
			this.dictionary.Add(discoveredType);
		}

		public ICollection<TypeName> TypesIn(string namespaceName)
		{
			return this.dictionary.ContentFor(namespaceName);
		}

		public ITypeDeclaration Lookup(TypeName typeName)
		{
			if (typeName == null)
			{
				throw new ArgumentNullException("typeName", "Type name cannot be blank");
			}

			return this.types.FirstOrDefault(x => x.TypeName.FullName == typeName.FullName);
		}

		public ICollection<TypeName> TypeDifferencesFrom(IntrospectedAssembly other)
		{
			if (other == null)
			{
				throw new ArgumentNullException("other", "Introspection object cannot be null");
			}

			return this.types.DifferencesFrom(other.types);
		}

		public ICollection<TypeName> TypesInCommonWith(IntrospectedAssembly other)
		{
			if (other == null)
			{
				throw new ArgumentNullException("other", "Introspection object cannot be null");
			}

			return this.types.InCommonWith(other.types);
		}

        public void Add(AssemblyReference ar)
        {
            this._references.Add(ar);
        }

		public override string ToString()
		{
			return string.Format("{0} Version={1}", this.Name, this.Version);
		}

		public override int GetHashCode()
		{
			return this.Name.GetHashCode() ^ this.Version.GetHashCode();
		}
	}
}
